/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package guzik.lukasz.SnpDetailedView;

import SnpDbEntities.Category;
import SnpDbEntities.CodeTypes;
import SnpDbEntities.Snippet;
import SnpDbEntities.User;
import SnpDbEntities.UserPermissions;
import guzik.lukasz.SnpDataAPI.SnpDataAPI;
import guzik.lukasz.SnpLoginEngine.interfaces.LoginEventListener;
import guzik.lukasz.snpexplorer.interfaces.SelectedItemListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.logging.Logger;
import org.openide.util.NbBundle;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;
//import org.openide.util.ImageUtilities;
import org.netbeans.api.settings.ConvertAsProperties;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.util.Lookup;

/**
 * Top component which displays something.
 */
@ConvertAsProperties(dtd = "-//guzik.lukasz.SnpDetailedView//SnpDetailedView//EN",
autostore = false)
public final class SnpDetailedViewTopComponent extends TopComponent implements
	LoginEventListener, SelectedItemListener
{
    private static SnpDetailedViewTopComponent instance;
    private Snippet actualSnippet = null;
    private boolean isPublicSnippet = false;
    private boolean descChanged = false;
    private boolean codeTypeChanged = false;
    /** path to the icon used by the component and its open action */
//    static final String ICON_PATH = "SET/PATH/TO/ICON/HERE";
    private static final String PREFERRED_ID = "SnpDetailedViewTopComponent";

    public SnpDetailedViewTopComponent()
    {
	initComponents();
	setName(NbBundle.getMessage(SnpDetailedViewTopComponent.class, "CTL_SnpDetailedViewTopComponent"));
	setToolTipText(NbBundle.getMessage(SnpDetailedViewTopComponent.class, "HINT_SnpDetailedViewTopComponent"));
//        setIcon(ImageUtilities.loadImage(ICON_PATH, true));
	//putClientProperty(TopComponent.PROP_CLOSING_DISABLED, Boolean.TRUE);

	initializeCodeTypes();
	setEditable(false);
	setButtonsEnabled(false);
	jOwnerField.setEditable(false);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jLabel2 = new javax.swing.JLabel();
        jScrollPane1 = new javax.swing.JScrollPane();
        jDescriptionField = new javax.swing.JTextPane();
        jOwnerField = new javax.swing.JTextField();
        jLabel3 = new javax.swing.JLabel();
        jTypeField = new javax.swing.JComboBox();
        jLabel4 = new javax.swing.JLabel();
        jSaveButton = new javax.swing.JButton();
        jDiscardButton = new javax.swing.JButton();

        org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(SnpDetailedViewTopComponent.class, "SnpDetailedViewTopComponent.jLabel2.text")); // NOI18N

        jDescriptionField.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyReleased(java.awt.event.KeyEvent evt) {
                jDescriptionFieldKeyReleased(evt);
            }
        });
        jScrollPane1.setViewportView(jDescriptionField);

        jOwnerField.setText(org.openide.util.NbBundle.getMessage(SnpDetailedViewTopComponent.class, "SnpDetailedViewTopComponent.jOwnerField.text")); // NOI18N

        org.openide.awt.Mnemonics.setLocalizedText(jLabel3, org.openide.util.NbBundle.getMessage(SnpDetailedViewTopComponent.class, "SnpDetailedViewTopComponent.jLabel3.text")); // NOI18N

        jTypeField.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
        jTypeField.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) {
                jTypeFieldItemStateChanged(evt);
            }
        });

        org.openide.awt.Mnemonics.setLocalizedText(jLabel4, org.openide.util.NbBundle.getMessage(SnpDetailedViewTopComponent.class, "SnpDetailedViewTopComponent.jLabel4.text")); // NOI18N

        org.openide.awt.Mnemonics.setLocalizedText(jSaveButton, org.openide.util.NbBundle.getMessage(SnpDetailedViewTopComponent.class, "SnpDetailedViewTopComponent.jSaveButton.text")); // NOI18N
        jSaveButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jSaveButtonActionPerformed(evt);
            }
        });

        org.openide.awt.Mnemonics.setLocalizedText(jDiscardButton, org.openide.util.NbBundle.getMessage(SnpDetailedViewTopComponent.class, "SnpDetailedViewTopComponent.jDiscardButton.text")); // NOI18N
        jDiscardButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jDiscardButtonActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(jLabel2)
                    .addComponent(jLabel3))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addComponent(jOwnerField, javax.swing.GroupLayout.DEFAULT_SIZE, 183, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jLabel4)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jTypeField, javax.swing.GroupLayout.PREFERRED_SIZE, 107, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 320, Short.MAX_VALUE))
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jSaveButton)
                    .addComponent(jDiscardButton))
                .addContainerGap())
        );

        layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {jDiscardButton, jSaveButton});

        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(jLabel2)
                            .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 59, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addGap(18, 18, 18)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(jOwnerField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(jLabel3)
                            .addComponent(jTypeField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(jLabel4)))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jSaveButton)
                        .addGap(18, 18, 18)
                        .addComponent(jDiscardButton)))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
    }// </editor-fold>//GEN-END:initComponents

    private void jDescriptionFieldKeyReleased(java.awt.event.KeyEvent evt)//GEN-FIRST:event_jDescriptionFieldKeyReleased
    {//GEN-HEADEREND:event_jDescriptionFieldKeyReleased
	if(actualSnippet == null)
	{
	    return;
	}

	if((jDescriptionField.getText().length() == 0 && actualSnippet.getDesc() == null)
		||jDescriptionField.getText().equals(actualSnippet.getDesc()))
	{
	    descChanged = false;
	    setButtonsEnabled(codeTypeChanged);
	} else
	{
	    descChanged = true;
	    setButtonsEnabled(true);
	}
    }//GEN-LAST:event_jDescriptionFieldKeyReleased

    private void jTypeFieldItemStateChanged(java.awt.event.ItemEvent evt)//GEN-FIRST:event_jTypeFieldItemStateChanged
    {//GEN-HEADEREND:event_jTypeFieldItemStateChanged
	if(actualSnippet == null)
	{
	    return;
	}

	if(codeTypesMap.get((String) jTypeField.getSelectedItem()) != actualSnippet.getCodeType())
	{
	    codeTypeChanged = true;
	    setButtonsEnabled(true);
	} else
	{
	    codeTypeChanged = false;
	    setButtonsEnabled(descChanged);
	}
    }//GEN-LAST:event_jTypeFieldItemStateChanged

    private void jSaveButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_jSaveButtonActionPerformed
    {//GEN-HEADEREND:event_jSaveButtonActionPerformed
	actualSnippet.setDesc(jDescriptionField.getText());
	actualSnippet.setCodeType(codeTypesMap.get((String) jTypeField.getSelectedItem()));
	setButtonsEnabled(false);
	if(!SnpDataAPI.getDefault().updateSnippet(actualSnippet, false, isPublicSnippet))
	{
	    NotifyDescriptor nd =
		    new NotifyDescriptor.Message("Nie udało się uaktualnić snippetu!",
		    NotifyDescriptor.ERROR_MESSAGE);
	    DialogDisplayer.getDefault().notify(nd);
	}
    }//GEN-LAST:event_jSaveButtonActionPerformed

    private void jDiscardButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_jDiscardButtonActionPerformed
    {//GEN-HEADEREND:event_jDiscardButtonActionPerformed
	jDescriptionField.setText(actualSnippet.getDesc());
	for(String item : codeTypesMap.keySet())
	{
	    if(actualSnippet.getCodeType() == codeTypesMap.get(item))
	    {
		jTypeField.setSelectedItem(item);
	    }
	}
	setButtonsEnabled(false);
    }//GEN-LAST:event_jDiscardButtonActionPerformed
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JTextPane jDescriptionField;
    private javax.swing.JButton jDiscardButton;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JTextField jOwnerField;
    private javax.swing.JButton jSaveButton;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JComboBox jTypeField;
    // End of variables declaration//GEN-END:variables
    private static HashMap<String, CodeTypes> codeTypesMap;

    /**
     * Gets default instance. Do not use directly: reserved for *.settings files only,
     * i.e. deserialization routines; otherwise you could get a non-deserialized instance.
     * To obtain the singleton instance, use {@link #findInstance}.
     */
    public static synchronized SnpDetailedViewTopComponent getDefault()
    {
	if(instance == null)
	{
	    instance = new SnpDetailedViewTopComponent();
	}
	return instance;
    }

    /**
     * Obtain the SnpDetailedViewTopComponent instance. Never call {@link #getDefault} directly!
     */
    public static synchronized SnpDetailedViewTopComponent findInstance()
    {
	TopComponent win = WindowManager.getDefault().findTopComponent(PREFERRED_ID);
	if(win == null)
	{
	    Logger.getLogger(SnpDetailedViewTopComponent.class.getName()).warning(
		    "Cannot find " + PREFERRED_ID + " component. It will not be located properly in the window system.");
	    return getDefault();
	}
	if(win instanceof SnpDetailedViewTopComponent)
	{
	    return (SnpDetailedViewTopComponent) win;
	}
	Logger.getLogger(SnpDetailedViewTopComponent.class.getName()).warning(
		"There seem to be multiple components with the '" + PREFERRED_ID
		+ "' ID. That is a potential source of errors and unexpected behavior.");
	return getDefault();
    }

    @Override
    public int getPersistenceType()
    {
	return TopComponent.PERSISTENCE_ALWAYS;
    }

    @Override
    public void componentOpened()
    {
	Lookup.getDefault().lookup(guzik.lukasz.SnpLoginEngine.interfaces.LoginEngineSPI.class).getLoginEngine().addLoginEventListener(instance);
	Lookup.getDefault().lookup(guzik.lukasz.snpexplorer.interfaces.SnpExplorerSPI.class).getSnpExplorer().addSelectedItemListener(instance);
    }

    @Override
    public void componentClosed()
    {
    }

    void writeProperties(java.util.Properties p)
    {
	// better to version settings since initial version as advocated at
	// http://wiki.apidesign.org/wiki/PropertyFiles
	p.setProperty("version", "1.0");
    }

    Object readProperties(java.util.Properties p)
    {
	if(instance == null)
	{
	    instance = this;
	}
	instance.readPropertiesImpl(p);
	return instance;
    }

    private void readPropertiesImpl(java.util.Properties p)
    {
	String version = p.getProperty("version");
    }

    @Override
    protected String preferredID()
    {
	return PREFERRED_ID;
    }

    private void setEditable(boolean editable)
    {
	jDescriptionField.setEditable(editable);
	jTypeField.setEnabled(editable);
    }

    private void setButtonsEnabled(boolean enabled)
    {
	jSaveButton.setEnabled(enabled);
	jDiscardButton.setEnabled(enabled);
    }

    private void initializeCodeTypes()
    {
	codeTypesMap = new HashMap<String, CodeTypes>();

	codeTypesMap.put("Plain text", CodeTypes.PLAIN);
	codeTypesMap.put("C", CodeTypes.C);
	codeTypesMap.put("C++", CodeTypes.CPP);
	codeTypesMap.put("HTML", CodeTypes.HTML);
	codeTypesMap.put("Java", CodeTypes.JAVA);
	codeTypesMap.put("Java Script", CodeTypes.JAVA_SCRIPT);
	codeTypesMap.put("LaTeX", CodeTypes.LATEX);
	codeTypesMap.put("SQL", CodeTypes.SQL);

	jTypeField.removeAllItems();
	Object[] entries = codeTypesMap.keySet().toArray();
	Arrays.sort(entries);
	for(Object entry : entries)
	{
	    jTypeField.addItem(entry);
	}
	jTypeField.setSelectedItem("Plain text");
    }

    @Override
    public void onLogin()
    {
    }

    @Override
    public void onLogout()
    {
	setEditable(false);
	setButtonsEnabled(false);
	jDescriptionField.setText("");
	jOwnerField.setText("");
	jTypeField.setSelectedItem("Plain text");
	actualSnippet = null;
    }

    @Override
    public void onSelectedSnippet(Snippet selectedSnippet, boolean isPublic)
    {
	User snippetOwner;
	isPublicSnippet = isPublic;
	if(selectedSnippet == null)
	{
	    setEditable(false);
	    jDescriptionField.setText("");
	    jOwnerField.setText("");
	    jTypeField.setSelectedItem("Plain text");
	    return;
	}

	if(actualSnippet != null && actualSnippet.getId() == selectedSnippet.getId())
	{
	    return;
	}

	UserPermissions connectedUsrPerms = SnpDataAPI.getDefault().getConnectedUser().getPermissions();
	if(!isPublic || connectedUsrPerms == UserPermissions.SUPER_ADMIN
		|| connectedUsrPerms == UserPermissions.ADMIN)
	{
	    setEditable(true);
	} else if(connectedUsrPerms == UserPermissions.MODERATOR)
	{
	    ArrayList<Integer> moderators;
	    moderators = SnpDataAPI.getDefault().getCategoryModerators(selectedSnippet.getCategoryId());
	    setEditable(moderators.contains(SnpDataAPI.getDefault().getConnectedUser().getId()));
	} else
	{
	    setEditable(false);
	}

	snippetOwner = SnpDataAPI.getDefault().getUser(selectedSnippet.getOwnerId());
	jDescriptionField.setText(selectedSnippet.getDesc());
	jOwnerField.setText(snippetOwner.getName() + " [" + snippetOwner.getLogin() + "]");
	for(String item : codeTypesMap.keySet())
	{
	    if(selectedSnippet.getCodeType() == codeTypesMap.get(item))
	    {
		jTypeField.setSelectedItem(item);
	    }
	}

	actualSnippet = selectedSnippet;
	descChanged = false;
	codeTypeChanged = false;
	setButtonsEnabled(false);
    }

    @Override
    public void onSelectedCategory(Category selectedCategory, boolean isPublic)
    {
	jDescriptionField.setText("");
	jOwnerField.setText("");
	jTypeField.setSelectedItem("Plain text");

	actualSnippet = null;
	descChanged = false;
	codeTypeChanged = false;
	
	setEditable(false);
	setButtonsEnabled(false);
    }
}
